/* * _______ _____ _____ _____ * |__ __| | __ \ / ____| __ \ * | | __ _ _ __ ___ ___ ___| | | | (___ | |__) | * | |/ _` | '__/ __|/ _ \/ __| | | |\___ \| ___/ * | | (_| | | \__ \ (_) \__ \ |__| |____) | | * |_|\__,_|_| |___/\___/|___/_____/|_____/|_| * * ------------------------------------------------------------- * * TarsosDSP is developed by Joren Six at IPEM, University Ghent * * ------------------------------------------------------------- * * Info: http://0110.be/tag/TarsosDSP * Github: https://github.com/JorenSix/TarsosDSP * Releases: http://0110.be/releases/TarsosDSP/ * * TarsosDSP includes modified source code by various authors, * for credits and info, see README. * */ package be.tarsos.dsp.example; import java.awt.BorderLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.UnsupportedAudioFileException; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.TitledBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import be.tarsos.dsp.AudioDispatcher; import be.tarsos.dsp.AudioEvent; import be.tarsos.dsp.AudioProcessor; import be.tarsos.dsp.GainProcessor; import be.tarsos.dsp.io.jvm.AudioDispatcherFactory; import be.tarsos.dsp.io.jvm.AudioPlayer; import be.tarsos.dsp.io.jvm.WaveformWriter; import be.tarsos.dsp.pitch.PitchProcessor; import be.tarsos.dsp.pitch.PitchProcessor.PitchEstimationAlgorithm; import be.tarsos.dsp.synthesis.PitchResyntheziser; /** * The resynthesizer example shows how to use the PitchResnthesizer class. It is * an application that extracts pitch from an audio file and resynthesizes it * using the envelope of the original signal and the pitch information. It can * be used to check pitch detection results. * * @author Joren Six * */ public class Resynthesizer{ /** * @param arguments * @throws InterruptedException * @throws InvocationTargetException */ public static void main(String... arguments) throws InterruptedException, InvocationTargetException { if(arguments.length==0){ SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { //ignore failure to set default look en feel; } JFrame frame = new GraphicalResynthesizer(); frame.pack(); frame.setSize(400,350); frame.setVisible(true); } }); }else{ new CommandLineResynthesizer(arguments); } } private static class GraphicalResynthesizer extends JFrame{ /** * */ private static final long serialVersionUID = 401554060116566946L; private final JSlider estimationGainSlider; private final JSlider sourceGainSlider; private AudioDispatcher estimationDispatcher; private AudioDispatcher sourceDispatcher; private GainProcessor estimationGain; private GainProcessor sourceGain; private final JFileChooser fileChooser; PitchEstimationAlgorithm algo; File currentFile; private ActionListener algoChangeListener = new ActionListener(){ @Override public void actionPerformed(final ActionEvent e) { String name = e.getActionCommand(); PitchEstimationAlgorithm newAlgo = PitchEstimationAlgorithm.valueOf(name); algo = newAlgo; if(currentFile!=null ){ estimationDispatcher.stop(); sourceDispatcher.stop(); startFile(currentFile); } }}; public GraphicalResynthesizer(){ this.setLayout(new BorderLayout()); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setTitle("Pitch Estimation Synthesizer"); estimationGainSlider = new JSlider(0,200); estimationGainSlider.setValue(100); estimationGainSlider.setPaintLabels(true); estimationGainSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { if (GraphicalResynthesizer.this.estimationDispatcher != null) { double gainValue = estimationGainSlider.getValue() / 100.0; estimationGain.setGain(gainValue); } } }); sourceGainSlider = new JSlider(0,200); sourceGainSlider.setValue(100); sourceGainSlider.setPaintLabels(true); sourceGainSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { if (GraphicalResynthesizer.this.sourceDispatcher != null) { double gainValue = sourceGainSlider.getValue() / 100.0; sourceGain.setGain(gainValue); } } }); JPanel fileChooserPanel = new JPanel(new BorderLayout()); fileChooserPanel.setBorder(new TitledBorder("1. Choose your audio (wav mono)")); fileChooser = new JFileChooser(); JButton chooseFileButton = new JButton("Choose a file..."); chooseFileButton.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { int returnVal = fileChooser.showOpenDialog(GraphicalResynthesizer.this); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fileChooser.getSelectedFile(); startFile(file); } else { //canceled } } }); fileChooserPanel.add(chooseFileButton,BorderLayout.CENTER); JPanel gainPanel = new JPanel(new GridLayout(2,2)); JLabel label = new JLabel("Gain source (in %)"); label.setToolTipText("Volume in % (100 is no change)."); gainPanel.add(label); gainPanel.add(sourceGainSlider); label = new JLabel("Gain estimations (in %)"); label.setToolTipText("Volume in % (100 is no change)."); gainPanel.add(label); gainPanel.add(estimationGainSlider); gainPanel.setBorder(new TitledBorder("3. Change the estimation / source")); this.add(fileChooserPanel,BorderLayout.NORTH); this.add(gainPanel,BorderLayout.SOUTH); JPanel pitchDetectionPanel = new PitchDetectionPanel(algoChangeListener); algo=PitchEstimationAlgorithm.YIN; this.add(pitchDetectionPanel,BorderLayout.CENTER); } protected void startFile(File file) { currentFile = file; AudioFormat format; try { format = AudioSystem.getAudioFileFormat(file).getFormat(); float samplerate = format.getSampleRate(); int size = 1024; int overlap = 0; PitchResyntheziser prs = new PitchResyntheziser(samplerate); estimationGain = new GainProcessor(estimationGainSlider.getValue()/100.0); estimationDispatcher = AudioDispatcherFactory.fromFile(file, size, overlap); estimationDispatcher.addAudioProcessor(new PitchProcessor(algo, samplerate, size, prs)); estimationDispatcher.addAudioProcessor(estimationGain); estimationDispatcher.addAudioProcessor(new AudioPlayer(format)); sourceGain = new GainProcessor(sourceGainSlider.getValue()/100.0); sourceDispatcher = AudioDispatcherFactory.fromFile(file, size, overlap); sourceDispatcher.addAudioProcessor(sourceGain); sourceDispatcher.addAudioProcessor(new AudioPlayer(format)); new Thread(estimationDispatcher).start(); new Thread(sourceDispatcher).start(); } catch (UnsupportedAudioFileException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (LineUnavailableException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private static class CommandLineResynthesizer { public CommandLineResynthesizer(String[] arguments) { checkArgumentsAndRun(arguments); } private void checkArgumentsAndRun(String... arguments){ if(arguments.length == 0){ printError(); } else { try { run(arguments); } catch (UnsupportedAudioFileException e) { printError(); SharedCommandLineUtilities.printLine(); System.err.println("Error:"); System.err.println("\tThe audio file is not supported!"); } catch (IOException e) { printError(); SharedCommandLineUtilities.printLine(); System.err.println("Current error:"); System.err.println("\tIO error, maybe the audio file is not found or not supported!"); } catch (IllegalArgumentException e) { printError(); SharedCommandLineUtilities.printLine(); System.err.println("Current error:"); System.err.println("\tThe algorithm provided is unknown!"); } catch (LineUnavailableException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private void combineTwoMonoAudioFilesInTwoChannels(String first,String second,String outputFile) throws IOException, UnsupportedAudioFileException, LineUnavailableException{ AudioInputStream stream = AudioSystem.getAudioInputStream(new File(first)); final float sampleRate = (int) stream.getFormat().getSampleRate(); final int numberOfSamples = (int) stream.getFrameLength(); //2 bytes per sample, stereo (2 channels) final byte[] byteBuffer = new byte[numberOfSamples * 2 * 2]; /* * Read the source file data in the left channel */ stream = AudioSystem.getAudioInputStream(new File(first)); byte[] sampleAsByteArray = new byte[2]; for (int sample = 0; sample < numberOfSamples; sample++) { stream.read(sampleAsByteArray); byteBuffer[sample * 4 + 0] = sampleAsByteArray[0]; byteBuffer[sample * 4 + 1] = sampleAsByteArray[1]; } /* * Read the source file data in the right channel */ stream = AudioSystem.getAudioInputStream(new File(second)); sampleAsByteArray = new byte[2]; for (int sample = 0; sample < numberOfSamples; sample++) { stream.read(sampleAsByteArray); byteBuffer[sample * 4 + 2] = sampleAsByteArray[0]; byteBuffer[sample * 4 + 3] = sampleAsByteArray[1]; } /* * Write the data to a file. */ final AudioFormat audioFormat = new AudioFormat(sampleRate, 16, 2, true, false); final ByteArrayInputStream bais = new ByteArrayInputStream(byteBuffer); final AudioInputStream audioInputStream = new AudioInputStream(bais, audioFormat, numberOfSamples); final File out = new File(outputFile); AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, out); audioInputStream.close(); } private void run(String[] args) throws UnsupportedAudioFileException, IOException, IllegalArgumentException, LineUnavailableException { PitchEstimationAlgorithm algo = PitchEstimationAlgorithm.FFT_YIN; String inputFile = args[0]; String outputFile = null; String combinedFile = null; if(args.length == 3 && args[0].equalsIgnoreCase("--detector")){ algo = PitchEstimationAlgorithm.valueOf(args[1].toUpperCase()); inputFile = args[2]; }else if(args.length == 3 && args[0].equalsIgnoreCase("--output")){ outputFile = args[1]; inputFile = args[2]; }else if(args.length == 5 && args[0].equalsIgnoreCase("--detector") && args[2].equalsIgnoreCase("--output")){ algo = PitchEstimationAlgorithm.valueOf(args[1].toUpperCase()); outputFile = args[3]; inputFile = args[4]; }else if(args.length == 7 && args[0].equalsIgnoreCase("--detector") && args[2].equalsIgnoreCase("--output") && args[4].equalsIgnoreCase("--combined")){ algo = PitchEstimationAlgorithm.valueOf(args[1].toUpperCase()); outputFile = args[3]; combinedFile = args[5]; inputFile = args[6]; } else if(args.length !=1){ printError(); SharedCommandLineUtilities.printLine(); System.err.println("Current error:"); System.err.println("\tThe command expects the options in the specified order, the current command is not parsed correctly!"); return; } File audioFile = new File(inputFile); AudioFormat format = AudioSystem.getAudioFileFormat(audioFile).getFormat(); float samplerate = format.getSampleRate(); int size = 1024; int overlap = 0; PitchResyntheziser prs = new PitchResyntheziser(samplerate); AudioDispatcher dispatcher = AudioDispatcherFactory.fromFile(audioFile, size, overlap); dispatcher.addAudioProcessor(new PitchProcessor(algo, samplerate, size, prs)); if(outputFile!=null){ dispatcher.addAudioProcessor(new WaveformWriter(format, outputFile)); }else{ dispatcher.addAudioProcessor(new AudioPlayer(format)); } dispatcher.addAudioProcessor(new AudioProcessor() { @Override public void processingFinished() {} @Override public boolean process(AudioEvent audioEvent) { System.err.print(String.format("%3.0f %%",audioEvent.getProgress() * 100)); System.err.print(String.format("\b\b\b\b\b",audioEvent.getProgress())); return true; } }); dispatcher.run(); if(combinedFile!=null){ combineTwoMonoAudioFilesInTwoChannels(inputFile, outputFile, combinedFile); } } private final void printError(){ SharedCommandLineUtilities.printPrefix(); System.err.println("Name:"); System.err.println("\tTarsosDSP resynthesizer"); SharedCommandLineUtilities.printLine(); System.err.println("Synopsis:"); System.err.println("\tjava -jar CommandLineResynthesizer.jar [--detector DETECTOR] [--output out.wav] [--combined combined.wav] input.wav"); SharedCommandLineUtilities.printLine(); System.err.println("Description:"); System.err.println("\tExtracts pitch and loudnes from audio and resynthesises the audio with that information.\n\t" + "The result is either played back our written in an output file. \n\t" + "There is als an option to combine source and synthezized material\n\t" + "in the left and right channels of a stereo audio file."); String descr=""; descr += "\n\n\tinput.wav\t\ta readable wav file."; descr += "\n\n\t--output out.wav\t\ta writable file."; descr += "\n\n\t--combined combined.wav\t\ta writable output file. One channel original, other synthesized."; descr += "\n\t--detector DETECTOR\tdefaults to FFT_YIN or one of these:\n\t\t\t\t"; for(PitchEstimationAlgorithm algo : PitchEstimationAlgorithm.values()){ descr += algo.name() + "\n\t\t\t\t"; } System.err.println(descr); } } }